<template>
    <div v-if="state.showClickCaptcha">
        <div class="click-captcha" :style="{ left: `calc(50% - ${state.captchaBoxLeft}px)`, top: `calc(50% - ${state.captchaBoxTop}px)` }">
            <div v-if="state.loading" class="loading">{{ 'Loading' }}</div>
            <div v-else class="captcha-img-box">
                <img
                    class="captcha-img"
                    :style="{ width: `${state.clickCaptchaInfo.width}px`, height: `${state.clickCaptchaInfo.height}px` }"
                    @click.prevent="onRecord($event)"
                    :src="state.clickCaptchaInfo.base64"
                    alt="请点击刷新"
                />
                <span
                    v-for="(item, index) in state.xy"
                    :key="index"
                    class="step"
                    @click="onCancelRecord(index)"
                    :style="`left:${parseFloat(item.split(',')[0]) - 13}px;top:${parseFloat(item.split(',')[1]) - 13}px`"
                >
                    {{ index + 1 }}
                </span>
            </div>
            <div class="captcha-prompt">
                {{ '请依次点击' }}
                <span v-for="(text, index) in state.clickCaptchaInfo.text" :key="index" :class="state.xy.length > index ? 'captcha-clicked' : ''">
                    {{ text }}
                </span>
            </div>
            <div class="captcha-refresh-box">
                <div class="captcha-refresh-line captcha-refresh-line-l"></div>
                <el-icon class="captcha-refresh-btn" @click="getClickCaptcha">
                    <el-icon-refresh />
                </el-icon>
                <div class="captcha-refresh-line captcha-refresh-line-r"></div>
            </div>
        </div>
        <div class="click-captcha-shade" @click="onClose"></div>
    </div>
</template>

<script setup lang="ts">
import { onMounted, reactive } from 'vue'
import passport from '@/api/modules/passport.ts'

// 定义State接口
interface State {
    clickCaptchaInfo: {
        id: string
        text: string
        base64: string
        width: number
        height: number
    }
    xy: string[]
    loading: boolean
    captchaBoxTop: number
    captchaBoxLeft: number
    showClickCaptcha: boolean
}
const state: State = reactive({
    clickCaptchaInfo: {
        id: '',
        text: '',
        base64: '',
        width: 350,
        height: 200
    },
    xy: [], // TypeScript会根据State接口自动推断为string[]类型
    loading: false,
    captchaBoxTop: 0,
    captchaBoxLeft: 0,
    showClickCaptcha: false
})

// 事件
const emit = defineEmits(['onLogin', 'closeClickCaptcha'])

onMounted(() => {
    getClickCaptcha()
})

function onRecord(event: MouseEvent) {
    if (state.xy.length < state.clickCaptchaInfo.text.length) {
        state.xy.push(event.offsetX + ',' + event.offsetY)
        if (state.xy.length === state.clickCaptchaInfo.text.length) {
            const targetElement = event.target as HTMLElement
            const captchaInfo = [state.xy.join('-'), targetElement.clientWidth, targetElement.clientHeight].join(';')
            emit('onLogin', {
                clickCaptchaInfo: state.clickCaptchaInfo,
                captchaInfo: captchaInfo
            })
        }
    }
}

function onCancelRecord(index: number) {
    state.xy.splice(index, 1)
}

function onClose() {
    emit('closeClickCaptcha')
}

// 点击验证码
async function getClickCaptcha() {
    state.xy = []
    state.loading = true
    state.clickCaptchaInfo = await passport.getClickCaptcha.get({ id: state.clickCaptchaInfo.id })

    state.captchaBoxLeft = (state.clickCaptchaInfo.width + 24) / 2
    state.captchaBoxTop = (state.clickCaptchaInfo.height + 200) / 2

    state.loading = false
    state.showClickCaptcha = true
}
</script>

<style scoped lang="scss">
.click-captcha {
    padding: 12px;
    border: 1px solid var(--el-border-color-extra-light);
    background-color: var(--el-color-white);
    position: fixed;
    z-index: 9999991;
    border-radius: 10px;
    box-shadow:
        0 0 0 1px hsla(0, 0%, 100%, 0.3) inset,
        0 0.5em 1em rgba(0, 0, 0, 0.6);

    .loading {
        color: var(--el-color-info);
        width: 350px;
        text-align: center;
        line-height: 200px;
    }

    .captcha-img-box {
        position: relative;

        .captcha-img {
            border: none;
            cursor: pointer;
        }

        .step {
            box-sizing: border-box;
            position: absolute;
            width: 20px;
            height: 20px;
            line-height: 20px;
            font-size: var(--el-font-size-small);
            font-weight: bold;
            text-align: center;
            color: var(--el-color-white);
            border: 1px solid var(--el-border-color-extra-light);
            background-color: var(--el-color-primary);
            border-radius: 30px;
            box-shadow: 0 0 10px var(--el-color-white);
            user-select: none;
            cursor: pointer;
        }
    }

    .captcha-prompt {
        height: 40px;
        line-height: 40px;
        font-size: var(--el-font-size-base);
        text-align: center;
        color: var(--el-color-info);

        span {
            margin-left: 10px;
            font-size: var(--el-font-size-medium);
            font-weight: bold;
            color: var(--el-color-error);

            &.captcha-clicked {
                color: var(--el-color-primary);
            }
        }
    }

    .captcha-refresh-box {
        position: relative;
        margin-top: 10px;

        .captcha-refresh-line {
            position: absolute;
            top: 16px;
            width: 140px;
            height: 1px;
            background-color: #ccc;
        }

        .captcha-refresh-line-l {
            left: 5px;
        }

        .captcha-refresh-line-r {
            right: 5px;
        }

        .captcha-refresh-btn {
            cursor: pointer;
            display: block;
            margin: 0 auto;
            width: 32px;
            height: 32px;
            font-size: 32px;
            color: var(--el-color-info);
        }
    }
}

.click-captcha-shade {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    width: 100vw;
    background-color: #00000080;
    z-index: 9999990;
}
</style>
